package com.zshan.clinic.common.util.validate;
import cn.hutool.core.date.ChineseDate;
import com.zshan.clinic.common.constant.CommonConstant;
import com.zshan.clinic.common.enums.GenderEnum;
import com.zshan.clinic.common.exception.BusinessFailException;
import com.zshan.clinic.common.util.string.StringUtil;

import java.time.LocalDate;
import java.time.Period;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.Date;

public class IdCardUtils {

    private static final String ID_CARD_REGEX = "^(\\d{15}|\\d{17}[\\dXx])$";
    private static final int[] WEIGHTS = {7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2};
    private static final char[] CHECK_CODES = {'1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2'};

    public static int getAgeMonthFromIdCard(String idCard) {
        LocalDate birthDate = extractBirthDate(idCard);
        if (birthDate == null) {
            return CommonConstant.DEFAULT_0;
        }
        Period period = Period.between(birthDate, LocalDate.now());
        return period.getMonths();
    }


    public static int getAgeYearFromIdCard(String idCard) {
        LocalDate birthDate = extractBirthDate(idCard);
        if (birthDate == null) {
            return CommonConstant.DEFAULT_0;
        }
        return Period.between(birthDate, LocalDate.now()).getYears();
    }



    /**
     * 校验身份证格式（15位或18位）
     */
    public static boolean isValidFormat(String idCard) {
        return idCard != null && idCard.matches(ID_CARD_REGEX);
    }

    /**
     * 将15位身份证号升级为18位，如果已是18位则原样返回
     */
    public static String convert15To18(String idCard) {
        if (StringUtil.isBlank(idCard)) {
            throw new BusinessFailException("身份证号不能为空");
        }
        if (idCard.length() == CommonConstant.DEFAULT_18) {
            return idCard;
        }
        if (idCard.length() != CommonConstant.DEFAULT_15) {
            return null;
        }
        String birth = "19" + idCard.substring(6, 12);
        String idCard17 = idCard.substring(0, 6) + birth + idCard.substring(12);
        return idCard17 + getCheckCode(idCard17);
    }

    /**
     * 计算18位身份证校验码
     */
    public static char getCheckCode(String idCard17) {
        int sum = 0;
        for (int i = 0; i < 17; i++) {
            sum += Character.getNumericValue(idCard17.charAt(i)) * WEIGHTS[i];
        }
        return CHECK_CODES[sum % 11];
    }

    /**
     * 验证18位身份证的校验码是否正确
     */
    public static boolean isValidCheckCode(String idCard18) {
        if (idCard18 == null || idCard18.length() != 18) {
            return false;
        }
        String idCard17 = idCard18.substring(0, 17);
        char expected = getCheckCode(idCard17);
        char actual = Character.toUpperCase(idCard18.charAt(17));
        return expected == actual;
    }

    /**
     * 提取出生日期（阳历）
     */
    public static LocalDate extractBirthDate(String idCard) {
        String id = idCard.length() == 15 ? convert15To18(idCard) : idCard;
        String birth = id.substring(6, 14);
        return LocalDate.parse(birth, DateTimeFormatter.ofPattern("yyyyMMdd"));
    }

    /**
     * 提取性别：1 = 男，2 = 女
     */
    public static String extractGender(String idCard) {
        String id = idCard.length() == 15 ? convert15To18(idCard) : idCard;
        int genderCode = Character.getNumericValue(id.charAt(16));
        return (genderCode % 2 == 0) ? GenderEnum.GIRL.getValue() : GenderEnum.BOY.getValue();
    }

    /**
     * 计算年龄
     */
    public static int calculateAge(String idCard) {
        LocalDate birthDate = extractBirthDate(idCard);
        return Period.between(birthDate, LocalDate.now()).getYears();
    }

    /**
     * 提取农历生日（格式 yyyy-MM-dd）
     */
    public static String convertToLunarYmd(LocalDate birthday) {
        Date date = Date.from(birthday.atStartOfDay(ZoneId.systemDefault()).toInstant());
        ChineseDate chineseDate = new ChineseDate(date);
        int year = chineseDate.getChineseYear();
        int month = chineseDate.getMonth();
        int day = chineseDate.getDay();
        return String.format("%04d-%02d-%02d", year, month, day);
    }

    /**
     * 从身份证中提取农历生日（以 LocalDate 返回，表示农历的年月日）
     */
    public static LocalDate extractLunarBirthday(String idCard) {
        LocalDate birthday = extractBirthDate(idCard); // 阳历生日
        return convertToLunarDate(birthday);           // 转换为农历 LocalDate（伪表示）
    }

    /**
     * 阳历转农历 LocalDate（表示农历的年月日，但不是公历日期）
     */
    public static LocalDate convertToLunarDate(LocalDate birthday) {
        Date date = Date.from(birthday.atStartOfDay(ZoneId.systemDefault()).toInstant());
        ChineseDate chineseDate = new ChineseDate(date);

        int year = chineseDate.getChineseYear();
        int month = chineseDate.getMonth();     // 农历月
        int day = chineseDate.getDay();         // 农历日

        // 注意：这个 LocalDate 并不是真正的阳历时间，只是用于统一表示农历的年月日
        return LocalDate.of(year, month, day);
    }

    // ==================== 测试入口 ====================
    public static void main(String[] args) {
        String id15 = "142625199203011134";
        String id18 = convert15To18(id15);

        System.out.println("➤ 原始15位: " + id15);
        System.out.println("➤ 转换18位: " + id18);
        System.out.println("➤ 格式是否正确: " + isValidFormat(id18));
        System.out.println("➤ 校验码是否正确: " + isValidCheckCode(id18));
        System.out.println("➤ 出生日期（阳历）: " + extractBirthDate(id18));
        System.out.println("➤ 农历生日: " + extractLunarBirthday(id18));
        System.out.println("➤ 性别: " + (extractGender(id18)));
        System.out.println("➤ 年龄: " + calculateAge(id18));
    }
}


